﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Diagnostics.Contracts;

namespace GBricks.Collections
{
  [Serializable]
  public class ReadOnlyKeyedCollection<TKey, TItem> : ReadOnlyCollection<TItem>
  {
    private static readonly ReadOnlyKeyedCollection<TKey, TItem> EmptyInstance = new ReadOnlyKeyedCollection<TKey, TItem>(new EmptyKeyedCollection());

    public ReadOnlyKeyedCollection(KeyedCollection<TKey, TItem> list)
      : base(list) {
      Argument.NotNull(list, "list");
    }

    public static ReadOnlyKeyedCollection<TKey, TItem> Empty {
      [DebuggerStepThrough]
      get {
        Contract.Ensures(Contract.Result<ReadOnlyKeyedCollection<TKey, TItem>>() != null);
        return EmptyInstance;
      }
    }

    protected new KeyedCollection<TKey, TItem> Items {
      [DebuggerStepThrough]
      get {
        Contract.Ensures(Contract.Result<KeyedCollection<TKey, TItem>>() != null);
        return (KeyedCollection<TKey, TItem>)base.Items;
      }
    }

    public IEqualityComparer<TKey> Comparer {
      [DebuggerStepThrough]
      get {
        Contract.Ensures(Contract.Result<IEqualityComparer<TKey>>() != null);
        Contract.Assume(Items.Comparer != null);
        return Items.Comparer;
      }
    }

    public TItem this[TKey key] {
      [DebuggerStepThrough]
      get { return Items[key]; }
    }

    [ContractInvariantMethod]
    private void Invariant() {
      Contract.Invariant(Items != null);
    }

    [Pure]
    public bool Contains(TKey key) {
      return Items.Contains(key);
    }

    [Serializable]
    private sealed class EmptyKeyedCollection : KeyedCollection<TKey, TItem>
    {
      protected override TKey GetKeyForItem(TItem item) {
        Throw.InvalidOperation();
        return default(TKey);
      }
    }
  }
}
